package the_Crash;

import java.util.HashMap;

import repast.simphony.engine.schedule.ScheduleParameters;
import repast.simphony.engine.schedule.ScheduledMethod;
import repast.simphony.random.RandomHelper;
import repast.simphony.space.continuous.ContinuousSpace;
import repast.simphony.space.grid.Grid;
import repast.simphony.space.grid.GridPoint;

public class SmartSignal extends Signal {
	
	protected HashMap<MovementStates,Integer> carWaitSum = new HashMap<MovementStates,Integer>();
	protected int cycleLength = 10;
	protected int cycleCount =0;
	
	public SmartSignal(GridPoint location, Grid<Object> grid,
			ContinuousSpace<Object> space) {
		super(location, grid, space);		
		cycleLength = ParameterResolver.getSmartCycleLength();
		legalStates.add(new Tuple<MovementStates>(MovementStates.NorthStraight, MovementStates.WestTurn));
		legalStates.add(new Tuple<MovementStates>(MovementStates.SouthStraight, MovementStates.EastTurn));
		legalStates.add(new Tuple<MovementStates>(MovementStates.WestStraight, MovementStates.SouthTurn));
		legalStates.add(new Tuple<MovementStates>(MovementStates.EastStraight, MovementStates.NorthTurn));
		resetCount();
	}
	
	//at the beginning of a tick, determine the state of the signal.  bases this on the sum
	//of the times that cars have been waiting in each direction.
	@ScheduledMethod (start = 1, interval = 1, priority = ScheduleParameters.FIRST_PRIORITY)
	public void step()
	{
		cycleCount++;
		if(cycleCount == cycleLength){
			currentState = legalStates.get(RandomHelper.nextIntFromTo(0,legalStates.size()-1));
			double currentBenefit = 0;
			double maxBenefit = 0;
			for(Tuple<MovementStates> t : legalStates)
			{
				currentBenefit = carWaitSum.get(t.getFirst());
				currentBenefit += carWaitSum.get(t.getSecond());
				if(currentBenefit>maxBenefit)
				{
					currentState=t;
					maxBenefit=currentBenefit;
				}
			}
			cycleCount = 0;
			this.resetCount();
		}
		
	}
	
	
	//allows the signal to keep track of how long a car has been waiting
	public void watchCar(int waitTime, Direction futureHeading, TravelDirection turn, Direction currentHeading)
	{
		MovementStates turnToMake = this.getTurnToMake(futureHeading, turn, currentHeading);
		carWaitSum.put(turnToMake, carWaitSum.get(turnToMake)+(int)Math.pow(waitTime,1.5));
	}
	
	private void resetCount()
	{
		carWaitSum = new HashMap<MovementStates,Integer>();
		for(MovementStates m: MovementStates.values())
			carWaitSum.put(m,0);
	}

	@Override
	public boolean isAboutToChange() {
		return cycleCount == cycleLength -5;
	}
	
	public boolean isOpen(Direction futureHeading, TravelDirection turn, Direction currentHeading){
		//we put the futureHeading and the turn to make into a single string and see if that state is open
		MovementStates turnToMake = this.getTurnToMake(futureHeading, turn, currentHeading);
		return this.currentState.getFirst().equals(turnToMake) || this.currentState.getSecond().equals(turnToMake);
	}

}
